using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Microsoft.Win32;

namespace Universe.JRun
{
    class JImpl
    {
        public static readonly string
            JRE = @"Software\JavaSoft\Java Runtime Environment",
            JDK = @"Software\JavaSoft\Java Development Kit";

        public static JDescriptions Read(string key, JDescription.JavaKind kind)
        {
            using(RegistryKey reg = Registry.LocalMachine.OpenSubKey(key, false))
            {
                if (reg != null)
                {
                    string currentVersion = ReadString(reg, "CurrentVersion");
                    string currentHome = null;

                    string[] subKeys = reg.GetSubKeyNames();
                    Array.Sort(subKeys, StringComparer.InvariantCultureIgnoreCase);

                    
                    List<JDescription> ret = new List<JDescription>();
                    foreach (string version in subKeys)
                    {
                        using(RegistryKey subKey = reg.OpenSubKey(version, false))
                        {
                            if (subKey != null)
                            {
                                string javaHome = ReadString(subKey, "JavaHome");
                                bool isLink = false;
                                foreach (JDescription description in ret)
                                {
                                    if (description.Path == javaHome)
                                        isLink = true;
                                }

                                if (version == currentVersion)
                                    currentHome = javaHome;

                                Version pv = null;
                                if (!isLink)
                                {
                                    object rawLib = subKey.GetValue("RuntimeLib");
                                    if (rawLib is string && kind == JDescription.JavaKind.JRE)
                                    {
                                        string lib = rawLib as string;
                                        if (File.Exists(lib))
                                        {
                                            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(lib);
                                            if (fvi.ProductVersion != null)
                                                pv = new Version(fvi.ProductVersion);
                                        }
                                    }
                                    else if (kind == JDescription.JavaKind.JDK)
                                    {
                                        string javac = Path.Combine(javaHome, "bin\\javac.exe");
                                        if (File.Exists(javac))
                                        {
                                            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(javac);
                                            if (fvi.ProductVersion != null)
                                                pv = new Version(fvi.ProductVersion);
                                        }

                                        if (pv == null && version.StartsWith("1.4"))
                                        {
                                            // JDK 1.4
                                            try
                                            {
                                                pv = new Version(version.Replace("_", "."));
                                            }
                                            catch
                                            {
                                            }
                                        }
                                    }

                                    ret.Add(new JDescription(kind, javaHome, version, pv));

                                }
                                    
                            }
                        }
                    }

                    foreach (JDescription description in ret)
                    {
                        description.IsCurrent = StringComparer.InvariantCultureIgnoreCase.Compare(description.Path, currentHome) == 0;
                        if (description.IsCurrent)
                            break;
                    }

                    ret.Sort(
                        delegate(JDescription x, JDescription y)
                            {
                                return x.ProductVersion == null || y.ProductVersion == null
                                    ? StringComparer.InvariantCultureIgnoreCase.Compare(x.Version, y.Version)
                                    : x.ProductVersion.CompareTo(y.ProductVersion);
                            });

                    return new JDescriptions(ret);
                }
                
            }

            return new JDescriptions();
        }

        static string ReadString(RegistryKey key, string name)
        {
            object raw = key.GetValue(name);
            return (string) (raw is string ? raw : null);
        }
    }
}
